#!/bin/bash
#
# Copyright (C) 2018 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
#
# SPDX-License-Identifier: LGPL-2.1-only

TEST_DESC="LTTng relayd filesystem grouping - Userspace tracing"

CURDIR=$(dirname "$0")/
TESTDIR=$CURDIR/../../..
NR_ITER=10
NR_USEC_WAIT=100
TESTAPP_PATH="$TESTDIR/utils/testapp"
TESTAPP_NAME="gen-ust-events"
TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
EVENT_NAME="tp:tptest"
CHANNEL_NAME="my_channel"

XPATH_CMD_OUTPUT="//lttng:command/lttng:output"
XPATH_SESSION="$XPATH_CMD_OUTPUT/lttng:sessions/lttng:session"

NUM_TESTS=254

source "$TESTDIR/utils/utils.sh"

if [ ! -x "$TESTAPP_BIN" ]; then
	BAIL_OUT "No UST events binary detected."
fi

function get_auto_session_name ()
{
	local __result=$1

	local lttng_bin=$LTTNG_BIN

	LTTNG_BIN="${lttng_bin} --mi xml"
	OUTPUT_DEST=$(mktemp -t "tmp.${FUNCNAME[0]}_output.XXXXXX")

	list_lttng_ok
	$MI_VALIDATE "$OUTPUT_DEST"
	ok $? "Valid lttng list XML"

	value=$($XML_EXTRACT "$OUTPUT_DEST" ${XPATH_SESSION}/lttng:name/text\(\))
	ok $? "Extraction of session name"
	rm -f $OUTPUT_DEST
	OUTPUT_DEST=/dev/null
	LTTNG_BIN=$lttng_bin

	# Transfer value to passed arguments
	eval "$__result='$value'"
}

function test_ust_uid_live ()
{
	local session_name="$1"
	local grouping="$2"

	diag "Test UST uid buffer live [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost --live

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-uid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_pid_live ()
{
	local session_name="$1"
	local grouping="$2"

	diag "Test UST pid buffer live [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost --live

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-pid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_live_custom_output ()
{
	local session_name="$1"
	local grouping="$2"
	local custom_output="my_live_custom_output"

	diag "Test UST uid buffer live, custom output [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost/$custom_output --live

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-uid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME-*/$custom_output"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$custom_output"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_streaming ()
{
	local session_name="$1"
	local grouping="$2"

	diag "Test UST uid buffer streaming [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-uid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_pid_streaming ()
{
	local session_name="$1"
	local grouping="$2"
	diag "Test UST pid buffer streaming [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-pid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_streaming_custom_output ()
{
	local session_name="$1"
	local grouping="$2"
	local custom_output="custom_second_token"

	diag "Test UST uid buffer streaming, custom output [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost/$custom_output

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-uid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME-*/$custom_output"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$custom_output"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_streaming_rotate ()
{
	local session_name="$1"
	local grouping="$2"

	diag "Test UST uid buffer rotate [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-uid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT
	rotate_session_ok "$session_name"

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_streaming_rotate_custom_output ()
{
	local session_name="$1"
	local grouping="$2"
	local custom_output="rotate_custom_path"

	diag "Test UST uid buffer rotate, custom output [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost/$custom_output

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-uid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT
	rotate_session_ok "$session_name"


	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME-*/$custom_output"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$custom_output"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_pid_streaming_rotate ()
{
	local session_name="$1"
	local grouping="$2"

	diag "Test UST pid buffer rotate with session_name [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-pid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT
	rotate_session_ok "$session_name"

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_streaming_snapshot ()
{
	local session_name="$1"
	local grouping="$2"

	diag "Test UST uid buffer snapshot streaming using 'create --snapshot' [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost --snapshot

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-uid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT
	lttng_snapshot_record "$session_name"

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_pid_streaming_snapshot ()
{
	local session_name="$1"
	local grouping="$2"

	local file_sync_after_first
	local file_sync_before_last

	file_sync_after_first=$(mktemp -u -t "tmp.${FUNCNAME[0]}_sync_after_first.XXXXXX")
	file_sync_before_last=$(mktemp -u -t "tmp.${FUNCNAME[0]}_sync_before_last.XXXXXX")

	diag "Test UST pid buffer snapshot streaming using 'create --snapshot' [$grouping][${session_name}]"

	create_lttng_session_uri "$session_name" net://localhost --snapshot

	enable_ust_lttng_channel_ok "$session_name" "$CHANNEL_NAME" "--buffers-pid"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT \
		--sync-after-first-event "$file_sync_after_first" \
		--sync-before-last-event "$file_sync_before_last" 2>&1 &

	while [ ! -f "${file_sync_after_first}" ]; do
		sleep 0.5
	done

	lttng_snapshot_record "$session_name"

	touch "$file_sync_before_last"
	wait

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME-*/snapshot-1*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*/snapshot-1*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi

	rm -f "$file_sync_after_first"
	rm -f "$file_sync_before_last"
}

function test_ust_uid_streaming_snapshot_add_output_default_name ()
{
	local session_name="$1"
	local grouping="$2"

	diag "Test UST uid buffer snapshot using 'add-output' with default snapshot name [$grouping][${session_name}]"

	create_lttng_session_no_output "$session_name"

	enable_lttng_mmap_overwrite_ust_channel "$session_name" "$CHANNEL_NAME"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	lttng_snapshot_add_output_ok "$session_name" "net://localhost"
	lttng_snapshot_record "$session_name"

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME-*/snapshot-1*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*/snapshot-1*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_streaming_snapshot_add_output_custom_name ()
{
	local session_name="$1"
	local grouping="$2"
	local snapshot_name="this_is_my_snapshot"

	diag "Test UST uid buffer snapshot using 'add-output' with custom snapshot name [$grouping][${session_name}]"

	create_lttng_session_no_output "$session_name"

	enable_lttng_mmap_overwrite_ust_channel "$session_name" "$CHANNEL_NAME"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	lttng_snapshot_add_output_ok "$session_name" "net://localhost" "-n $snapshot_name"
	lttng_snapshot_record "$session_name"

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	# When session name is automatic, the actual directory is "auto", not
	# auto-<datetime>.
	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME-*/$snapshot_name*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$session_name*/$snapshot_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

function test_ust_uid_streaming_snapshot_add_output_custom_name_custom_output ()
{
	local session_name="$1"
	local grouping="$2"
	local snapshot_name="this_is_my_snapshot"
	local custom_output="this/is/my/custom/path"

	diag "Test UST uid buffer snapshot using 'add-output' with custom snapshot name and custom output path [$grouping][${session_name}]"

	create_lttng_session_no_output "$session_name"

	enable_lttng_mmap_overwrite_ust_channel "$session_name" "$CHANNEL_NAME"
	enable_ust_lttng_event_ok "$session_name" "$EVENT_NAME" "$CHANNEL_NAME"
	start_lttng_tracing_ok "$session_name"

	$TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT

	lttng_snapshot_add_output_ok "$session_name" "net://localhost/$custom_output" "-n $snapshot_name"
	lttng_snapshot_record "$session_name"

	stop_lttng_tracing_ok "$session_name"
	destroy_lttng_session_ok "$session_name" --no-wait

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$session_name/$HOSTNAME-*/$custom_output/$snapshot_name*"
	else
		validate_trace "$EVENT_NAME" "$TRACE_PATH/$HOSTNAME/$custom_output/$snapshot_name*"
	fi

	if [ "$grouping" = "$GROUP_BY_SESSION" ]; then
		rm -rf "${TRACE_PATH:?}/$session_name"
	else
		rm -rf "${TRACE_PATH:?}/$HOSTNAME"
	fi
}

plan_tests $NUM_TESTS

print_test_banner "$TEST_DESC"

bail_out_if_no_babeltrace

tests=(
	test_ust_uid_live
	test_ust_pid_live
	test_ust_uid_live_custom_output
	test_ust_uid_streaming
	test_ust_pid_streaming
	test_ust_uid_streaming_custom_output
	test_ust_uid_streaming_rotate
	test_ust_uid_streaming_rotate_custom_output
	test_ust_pid_streaming_rotate
	test_ust_uid_streaming_snapshot
	test_ust_pid_streaming_snapshot
	test_ust_uid_streaming_snapshot_add_output_default_name
	test_ust_uid_streaming_snapshot_add_output_custom_name
	test_ust_uid_streaming_snapshot_add_output_custom_name_custom_output
)

GROUP_BY_SESSION="--group-output-by-session"
GROUP_BY_HOSTNAME="--group-output-by-host"

grouping_types=(
	$GROUP_BY_SESSION
	$GROUP_BY_HOSTNAME
)
for grouping in "${grouping_types[@]}";
do
	TRACE_PATH=$(mktemp -d -t tmp.test_relayd_grouping_ust_trace_path.XXXXXX)
	# Set the relayd in --group-output-by-session mode
	start_lttng_relayd "-o $TRACE_PATH $grouping"
	start_lttng_sessiond
	for fct_test in "${tests[@]}";
	do
		# Perform test when session name is given
		name="my-session"
		${fct_test} "$name" "$grouping"
		count=$(find "$TRACE_PATH/" -maxdepth 1 -mindepth 1 | wc -l)
		is "$count" "0" "LTTng-relayd output directory empty"
	done
	rm -rf "$TRACE_PATH"
	stop_lttng_relayd
	stop_lttng_sessiond
done
